package com.sinoframework.web.servlet.advice;

import com.alibaba.fastjson.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.sinoframework.web.servlet.bean.ExtIterApiRuntimeException;
import com.sinoframework.web.servlet.bean.Response;
import com.sinoframework.web.servlet.bean.SinoFailRuntimeException;
 
/**
 * 全局异常捕获处理
 * ExceptionHandlerExceptionResolver类 的initExceptionHandlerAdviceCache()方法会扫描@ControllerAdvice注解
 * 
 * ResponseEntity一定不能添加泛型，否则会被ResponseControllerAdvice 类在把返回值包装一次
 * 
 */
@RestControllerAdvice
public class SinoGlobalExceptionHandler {
	private static final Logger log = LogManager.getLogger();

	private static final String CONTENT_TYPE = "Content-Type";

    
    
    
    public SinoGlobalExceptionHandler() {
    	log.info("启用【SinoGlobalExceptionHandler 全局异常】");
	}

	/**
     * 	返回自定义异常信息
     * @param ex
     * @return
     */
    @ExceptionHandler(value = SinoFailRuntimeException.class)
    public ResponseEntity<Object> errorHandler(Exception ex) {
		log.info("全局异常【线程名：{}】 【异常信息：{}】  【异常位置：{}】",Thread.currentThread().getName(),ex.getMessage(),ex.getStackTrace()[0]);
    	HttpHeaders headers = new HttpHeaders();
        headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        return new ResponseEntity<>(Response.makeOKRsp(ex.getMessage()),headers, HttpStatus.BAD_REQUEST);
    }

    /**
     * 参数校验失败
     * @param ex
     * @return
     */
    @ExceptionHandler(value = {BindException.class} )
    public ResponseEntity<Object> bindException(BindException ex){
        JSONObject jsonObject = new JSONObject();
        ex.getBindingResult()
                .getFieldErrors()
                .forEach(fieldError -> jsonObject.put(fieldError.getField(),fieldError.getDefaultMessage()));

        HttpHeaders headers = new HttpHeaders();
        headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        return new ResponseEntity<>(Response.makeOKRsp(ex.getMessage()),headers, HttpStatus.BAD_REQUEST);
    }
    /**
     * 参数校验失败
     * @param ex
     * @return
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class } )
    public ResponseEntity<Object> methodArgumentException(MethodArgumentNotValidException ex){
        JSONObject jsonObject = new JSONObject();
        ex.getBindingResult()
                .getFieldErrors()
                .forEach(fieldError -> jsonObject.put(fieldError.getField(),fieldError.getDefaultMessage()));

        HttpHeaders headers = new HttpHeaders();
        headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        return new ResponseEntity<>(Response.makeOKRsp(ex.getMessage()),headers, HttpStatus.BAD_REQUEST);
    }


    /**
     * 	返回自定义异常信息
     * @param ex
     * @return
     */
    @ExceptionHandler(value = ExtIterApiRuntimeException.class)
    public ResponseEntity<Object> extIterHandler(Exception ex) {
		log.info("全局异常【线程名：{}】 【异常信息：{}】  【异常位置：{}】",Thread.currentThread().getName(),ex.getMessage(),ex.getStackTrace()[0]);
    	
    	HttpHeaders headers = new HttpHeaders();
        headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        return new ResponseEntity<>(Response.makeExtIterApiRsp(),headers, HttpStatus.BAD_REQUEST);
    }
    
    /**
     * 	返回固定异常信息：稍后重试
     * @param ex
     * @return
     * @throws Exception 
     */
    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<Object> allExceptionHandler(Exception ex) throws Throwable{
    	
    	  //不处理spring security异常直接跑出交由：customAccessDeniedHandler和customAuthenticationEntryPoint处理 AuthenticationException AccessDeniedException
    	  if(ex.getClass().getPackage().getName().startsWith("org.springframework.security")) {
    		  throw ex;
    	  }

		  log.info("全局异常【线程名：{}】 【异常信息：{}】  【异常位置：{}】",Thread.currentThread().getName(),ex.getMessage(),ex.getStackTrace()[0]);
	      HttpHeaders headers = new HttpHeaders();
	      headers.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
	      return new ResponseEntity<>(Response.makeErrotRsp(),headers, HttpStatus.INTERNAL_SERVER_ERROR);
    	
    }
    
}
